﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace Sidvall.UI.Wpf.Controls
{
    public partial class ExtendedCheckBoxControl : UserControl, INotifyPropertyChanged
    {
        #region Public Members

        public event PropertyChangedEventHandler PropertyChanged;

        #region DisplayMode

        public static readonly System.Windows.DependencyProperty DisplayModeProperty = System.Windows.DependencyProperty.Register(nameof(DisplayMode), typeof(ExtendedCheckBoxDisplayMode), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(ExtendedCheckBoxDisplayMode.TrueFalse, System.Windows.FrameworkPropertyMetadataOptions.None,
                OnDisplayModeChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public ExtendedCheckBoxDisplayMode DisplayMode
        {
            get
            {
                return (ExtendedCheckBoxDisplayMode)GetValue(DisplayModeProperty);
            }
            set
            {
                SetValue(DisplayModeProperty, value);
            }
        }

        #endregion
        #region ItemMargin

        public static readonly System.Windows.DependencyProperty ButtonMarginProperty = System.Windows.DependencyProperty.Register(nameof(ItemMargin), typeof(Thickness), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(new Thickness(8, 0, 0, 0), System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public Thickness ItemMargin
        {
            get
            {
                return (Thickness)GetValue(ButtonMarginProperty);
            }
            set
            {
                SetValue(ButtonMarginProperty, value);
            }
        }

        #endregion
        #region ItemOrientation

        public static readonly System.Windows.DependencyProperty ItemOrientationProperty = System.Windows.DependencyProperty.Register(nameof(ItemOrientation), typeof(System.Windows.Controls.Orientation), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(System.Windows.Controls.Orientation.Horizontal, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public System.Windows.Controls.Orientation ItemOrientation
        {
            get
            {
                return (System.Windows.Controls.Orientation)GetValue(ItemOrientationProperty);
            }
            set
            {
                SetValue(ItemOrientationProperty, value);
            }
        }

        #endregion
        #region LabelMargin

        public static readonly System.Windows.DependencyProperty LabelMarginProperty = System.Windows.DependencyProperty.Register(nameof(LabelMargin), typeof(Thickness), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(new Thickness(0, 0, 0, 0), System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public Thickness LabelMargin
        {
            get
            {
                return (Thickness)GetValue(LabelMarginProperty);
            }
            set
            {
                SetValue(LabelMarginProperty, value);
            }
        }

        #endregion
        #region LabelText

        public static readonly System.Windows.DependencyProperty LabelTextProperty = System.Windows.DependencyProperty.Register(nameof(LabelText), typeof(string), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, OnLabelTextPropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string LabelText
        {
            get
            {
                return GetValue(LabelTextProperty) as string;
            }
            set
            {
                SetValue(LabelTextProperty, value);
            }
        }

        #endregion
        #region LabelLeftContent

        public static readonly System.Windows.DependencyProperty LabelLeftContentProperty = System.Windows.DependencyProperty.Register(nameof(LabelLeftContent), typeof(object), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public object LabelLeftContent
        {
            get
            {
                return GetValue(LabelLeftContentProperty);
            }
            set
            {
                SetValue(LabelLeftContentProperty, value);
            }
        }

        #endregion
        #region LabelRightContent

        public static readonly System.Windows.DependencyProperty LabelRightContentProperty = System.Windows.DependencyProperty.Register(nameof(LabelRightContent), typeof(object), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public object LabelRightContent
        {
            get
            {
                return GetValue(LabelRightContentProperty);
            }
            set
            {
                SetValue(LabelRightContentProperty, value);
            }
        }

        #endregion

        #region IsChecked

        public static readonly System.Windows.DependencyProperty IsCheckedProperty = System.Windows.DependencyProperty.Register(nameof(IsChecked), typeof(bool?), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnIsCheckedPropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public bool? IsChecked
        {
            get
            {
                return GetValue(IsCheckedProperty) as bool?;
            }
            set
            {
                SetValue(IsCheckedProperty, value);
            }
        }

        #endregion
        #region IsNullable

        public static readonly System.Windows.DependencyProperty IsNullableProperty = System.Windows.DependencyProperty.Register(nameof(IsNullable), typeof(bool), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(true, System.Windows.FrameworkPropertyMetadataOptions.None,
                OnIsNullablePropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public bool IsNullable
        {
            get
            {
                return (bool)GetValue(IsNullableProperty);
            }
            set
            {
                SetValue(IsNullableProperty, value);
            }
        }

        #endregion
        #region Value1Caption

        public static readonly System.Windows.DependencyProperty Value1CaptionProperty = System.Windows.DependencyProperty.Register(nameof(Value1Caption), typeof(string), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string Value1Caption
        {
            get
            {
                return GetValue(Value1CaptionProperty) as string;
            }
            set
            {
                SetValue(Value1CaptionProperty, value);
            }
        }

        #endregion
        #region Value2Caption

        public static readonly System.Windows.DependencyProperty Value2CaptionProperty = System.Windows.DependencyProperty.Register(nameof(Value2Caption), typeof(string), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string Value2Caption
        {
            get
            {
                return GetValue(Value2CaptionProperty) as string;
            }
            set
            {
                SetValue(Value2CaptionProperty, value);
            }
        }

        #endregion
        #region Value3Caption

        public static readonly System.Windows.DependencyProperty Value3CaptionProperty = System.Windows.DependencyProperty.Register(nameof(Value3Caption), typeof(string), typeof(ExtendedCheckBoxControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string Value3Caption
        {
            get
            {
                return GetValue(Value3CaptionProperty) as string;
            }
            set
            {
                SetValue(Value3CaptionProperty, value);
            }
        }

        #endregion
        #region IsValue1Checked

        public bool? IsValue1Checked
        {
            get
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.TrueFalse:
                    case ExtendedCheckBoxDisplayMode.TrueFalseNull:
                        if (this.IsChecked == true)
                            return true;
                        break;
                    case ExtendedCheckBoxDisplayMode.FalseTrue:
                    case ExtendedCheckBoxDisplayMode.FalseTrueNull:
                        if (this.IsChecked == false)
                            return true;
                        break;
                    default:
                        if (this.IsChecked == null)
                            return true;
                        break;
                }
                return false;
            }
            set
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.TrueFalse:
                    case ExtendedCheckBoxDisplayMode.TrueFalseNull:
                        if (value == true)
                        {
                            this.IsChecked = true;
                        }
                        else if ((value == false) && (this.IsChecked == true) && (this.AllowNullValue))
                        {
                            this.IsChecked = null;
                        }
                        break;
                    case ExtendedCheckBoxDisplayMode.FalseTrue:
                    case ExtendedCheckBoxDisplayMode.FalseTrueNull:
                        if (value == true)
                        {
                            this.IsChecked = false;
                        }
                        else if ((value == false) && (this.IsChecked == false) && (this.AllowNullValue))
                        {
                            this.IsChecked = null;
                        }
                        break;
                    default:
                        if (value == true)
                            this.IsChecked = null;
                        break;
                }
            }
        }

        #endregion
        #region IsValue2Checked

        public bool? IsValue2Checked
        {
            get
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.FalseTrue:
                    case ExtendedCheckBoxDisplayMode.FalseTrueNull:
                        if (this.IsChecked == true)
                            return true;
                        break;
                    case ExtendedCheckBoxDisplayMode.TrueFalse:
                    case ExtendedCheckBoxDisplayMode.TrueFalseNull:
                        if (this.IsChecked == false)
                            return true;
                        break;
                    default:
                        if (this.IsChecked == null)
                            return true;
                        break;
                }
                return false;
            }
            set
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.FalseTrue:
                    case ExtendedCheckBoxDisplayMode.FalseTrueNull:
                        if (value == true)
                        {
                            this.IsChecked = true;
                        }
                        else if ((value == false) && (this.IsChecked == true) && (this.AllowNullValue))
                        {
                            this.IsChecked = null;
                        }
                        break;
                    case ExtendedCheckBoxDisplayMode.TrueFalse:
                    case ExtendedCheckBoxDisplayMode.TrueFalseNull:
                        if (value == true)
                        {
                            this.IsChecked = false;
                        }
                        else if ((value == false) && (this.IsChecked == false) && (this.AllowNullValue))
                        {
                            this.IsChecked = null;
                        }
                        break;
                    default:
                        if (value == true)
                            this.IsChecked = null;
                        break;
                }
            }
        }

        #endregion
        #region IsValue3Checked

        public bool? IsValue3Checked
        {
            get
            {
                if (this.IsChecked == null)
                    return true;
                return false;
            }
            set
            {
                if (value == true)
                    this.IsChecked = null;
            }
        }

        #endregion
        #region Value3Visibility

        public Visibility Value3Visibility
        {
            get
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.TrueFalse:
                    case ExtendedCheckBoxDisplayMode.FalseTrue:
                        return Visibility.Collapsed;
                    default:
                        return Visibility.Visible;
                }
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region AllowNullValue

        private bool AllowNullValue
        {
            get
            {
                switch (this.DisplayMode)
                {
                    case ExtendedCheckBoxDisplayMode.TrueFalseNull:
                    case ExtendedCheckBoxDisplayMode.FalseTrueNull:
                        return false;
                    default:
                        return this.IsNullable;
                }
            }
        }

        #endregion

        #region InitializeLabel

        private static void InitializeLabel(ExtendedCheckBoxControl parent)
        {
            if (string.IsNullOrEmpty(parent.LabelText))
            {
                parent.Label.Visibility = Visibility.Collapsed;
            }
            else
            {
                parent.Label.Visibility = Visibility.Visible;
            }
        }

        #endregion

        #region OnDisplayModeChanged

        private static void OnDisplayModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var parent = d as ExtendedCheckBoxControl;
            if (parent == null)
                return;
            parent.OnPropertyChanged();
        }

        #endregion
        #region OnIsCheckedPropertyChanged

        private static void OnIsCheckedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var parent = d as ExtendedCheckBoxControl;
            if (parent == null)
                return;
            parent.OnPropertyChanged();
        }

        #endregion
        #region OnIsNullablePropertyChanged

        private static void OnIsNullablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var parent = d as ExtendedCheckBoxControl;
            if (parent == null)
                return;
            parent.OnPropertyChanged();
        }

        #endregion
        #region OnLabelTextPropertyChanged

        private static void OnLabelTextPropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            var parent = d as ExtendedCheckBoxControl;
            if (parent == null)
                return;
            InitializeLabel(parent);
        }

        #endregion
        #region OnPropertyChanged

        protected void OnPropertyChanged()
        {
            OnPropertyChanged(nameof(IsValue1Checked));
            OnPropertyChanged(nameof(IsValue2Checked));
            OnPropertyChanged(nameof(IsValue3Checked));
            OnPropertyChanged(nameof(Value3Visibility));
        }
        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
        protected void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged.Invoke(this, args);
        }

        #endregion

        #endregion
        #region Constructors

        public ExtendedCheckBoxControl()
        {
            InitializeComponent();
        }

        #endregion
    }
}
